from rbac import models
from django.shortcuts import render,redirect,HttpResponse
from django.urls import reverse
from rbac.forms.menu import MenuModelForm,SecondMenuModelForm,PermissionModelForm,MultiAddPermissionForm,MultiEditPermissionForm
from rbac.service.urls import memory_reverse
from rbac.service.routes import get_all_url_dict
from collections import OrderedDict
from django.forms import formset_factory
from django.conf import settings
from django.utils.module_loading import  import_string



def menu_list(request):
    '''
    菜单和权限列表
    :param request:
    :return:
    '''

    menus = models.Menu.objects.all()
    menu_id = request.GET.get('mid')   # 用户选择的一级菜单
    second_menu_id = request.GET.get('sid')   # 用户选择的一级菜单


    # 判断menu_id是否在数据库存在
    menu_exists = models.Menu.objects.filter(id=menu_id).exists()
    if not menu_exists:
        menu_id = None

    # 判断second_menu_id是否在数据库存在
    second_menu_exists = models.Permission.objects.filter(id=second_menu_id).exists()
    if not menu_exists:
        second_menu_id = None

    # 判断一级菜单是否选中
    if menu_id:
        second_menus = models.Permission.objects.filter(menu_id=menu_id)
    else:
        second_menus = []

    # 判断二级菜单是否选中
    if second_menu_id:
        permissions = models.Permission.objects.filter(pid_id=second_menu_id)
    else:
        permissions = []
    return render(request,'rbac/menu_list.html',locals())


def menu_add(request):
    '''
    添加一级菜单
    :param request:
    :return:
    '''
    if request.method == 'GET':
        form = MenuModelForm()
        return render(request, 'rbac/change.html', {'form':form})


    form = MenuModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request,'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def menu_edit(request,pk):
    '''
    编辑一级菜单
    :param request:
    :return:
    '''
    obj = models.Menu.objects.filter(id=pk).first()
    if not obj:
        return HttpResponse("菜单不存在")
    if request.method == "GET":
        form = MenuModelForm(instance=obj)
        return render(request, 'rbac/change.html', {'form':form})
    form = MenuModelForm(instance=obj,data=request.POST)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request,'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def menu_del(request,pk):
    '''
    删除一级菜单
    :param request:
    :return:
    '''
    url = memory_reverse(request,'rbac:menu_list')
    if request.method == "GET":
        return render(request,'rbac/delete.html',{'cancel':url})
    models.Menu.objects.filter(id=pk).delete()
    return redirect(url)


def second_menu_add(request,menu_id):
    '''
    添加二级菜单
    :param request:
    :param menu_id:已选择的一级菜单ID（用于展示默认值）
    :return:
    '''

    menu_object = models.Menu.objects.filter(id=menu_id).first()


    if request.method == 'GET':
        form = SecondMenuModelForm(initial={'menu':menu_object})
        return render(request, 'rbac/change.html', {'form': form})

    form = SecondMenuModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def second_menu_edit(request,pk):
    '''
    编辑二级菜单
    :param request:
    :param pk:当前要编辑的二级菜单
    :return:
    '''

    permission_object = models.Permission.objects.filter(id=pk).first()


    if request.method == 'GET':
        form = SecondMenuModelForm(instance=permission_object)
        return render(request, 'rbac/change.html', {'form': form})

    form = SecondMenuModelForm(data=request.POST,instance=permission_object)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def second_menu_del(request,pk):
    '''
    删除二级菜单
    :param request:
    :return:
    '''
    url = memory_reverse(request, 'rbac:menu_list')
    if request.method == "GET":
        return render(request, 'rbac/delete.html', {'cancel': url})
    models.Permission.objects.filter(id=pk).delete()
    return redirect(url)


def permission_add(request,second_menu_id):
    '''
    添加权限
    :param request:
    :param second_menu_id:
    :return:
    '''

    if request.method == 'GET':
        form = PermissionModelForm()
        return render(request, 'rbac/change.html', {'form': form})

    form = PermissionModelForm(data=request.POST)
    if form.is_valid():
        second_menu_object = models.Permission.objects.filter(id=second_menu_id).first()
        if not second_menu_object:
            return HttpResponse("二级菜单不存在，请重新选择")

        # form.instance中包含了用户提交的所有值
        form.instance.pid = second_menu_object   # 这一步相当于把second_menu_object的二级菜单id当做pid保存在数据库里了

        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def permission_edit(request,pk):
    '''
    编辑权限
    :param request:
    :param pk: 当前要编辑的权限ID
    :return:
    '''
    permission_object = models.Permission.objects.filter(id=pk).first()


    if request.method == 'GET':
        form = PermissionModelForm(instance=permission_object)
        return render(request, 'rbac/change.html', {'form': form})

    form = PermissionModelForm(data=request.POST,instance=permission_object)
    if form.is_valid():
        form.save()
        return redirect(memory_reverse(request, 'rbac:menu_list'))
    return render(request, 'rbac/change.html', {'form': form})


def permission_del(request,pk):
    '''
    删除权限
    :param request:
    :param pk: 当前要删除的权限ID
    :return:
    '''
    url = memory_reverse(request, 'rbac:menu_list')
    if request.method == "GET":
        return render(request, 'rbac/delete.html', {'cancel': url})
    models.Permission.objects.filter(id=pk).delete()
    return redirect(url)


def multi_permissions(request):
    '''
    批量操作权限
    :param request:
    :return:
    '''
    post_type = request.GET.get('type')
    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)

    generate_formset = None
    update_formset = None

    if request.method == 'POST' and post_type == 'generate':
        # 批量添加
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            object_list = []
            has_error = False   # 判断是否存在异常的标识
            post_row_list = formset.cleaned_data     # 获取提交的数据
            for i in range(0,formset.total_form_count()):
                row_dict = post_row_list[i]
                try:       # 判断提交过来的数据 是否存在唯一值的情况
                    new_object = models.Permission(**row_dict)
                    new_object.validate_unique()
                    object_list.append(new_object)
                except Exception as e:
                    formset.errors[i].update(e)
                    generate_formset = formset
                    has_error = True

            if not has_error:
                # 对数据库进行批量增加，batch_size = 10 表示对数据库一次增加10条
                models.Permission.objects.bulk_create(object_list,batch_size=100)
        else:
            generate_formset = formset

    if request.method == 'POST' and post_type == 'update':
        # 批量更新
        formset = update_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            for i in range(0,formset.total_form_count()):
                row_dict = post_row_list[i]
                permission_id = row_dict.pop('id')  # 拿掉id
                try:
                    row_object = models.Permission.objects.filter(id = permission_id).first()
                    for k,v in row_dict.items():
                        setattr(row_object,k,v)
                    row_object.validate_unique()
                    row_object.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    update_formset = formset

        else:
            update_formset = formset



    # 1.获取项目中所有URL
    all_url_dict = get_all_url_dict()
    """
    {
        'rbac:role_list':{'name': 'rbac:role_list', 'url': '/rbac/role/list/'},
        'rbac:role_add':{'name': 'rbac:role_add', 'url': '/rbac/role/add/'},......
    }
    """

    router_name_set = set(all_url_dict.keys())

    # 2.获取数据库中的所有URL
    permission = models.Permission.objects.all().values('id','title','name','url','menu_id','pid_id')
    permission_dict = OrderedDict()
    for row in permission:
        permission_dict[row['name']] = row

    '''
    {
        'rbac:role_list':{'id':1,'title':'角色列表','name':'rbac:role_list',url....},
    }
    '''
    permission_name_set = set(permission_dict.keys())

    for name,value in permission_dict.items():
        router_row_dict = all_url_dict.get(name)
        if not router_row_dict:
            continue
        if value['url'] != router_row_dict['url']:
            print('数据库中',value['url'])
            print('项目中',router_row_dict['url'])
            value['url'] = '路由和数据库中不一致，请检查'

    # 3.应该添加、删除、修改的权限有哪些？

    # 需要添加的
    if not generate_formset:
        generate_name_list = router_name_set - permission_name_set
        generate_formset = generate_formset_class(initial=[row_dict for name, row_dict in all_url_dict.items() if name in generate_name_list])

    # 需要删除的
    delete_name_list = permission_name_set - router_name_set
    delete_row_list = [row_dict for name,row_dict in permission_dict.items() if name in delete_name_list]

    # 需要更新的
    if not update_formset:
        update_name_list = permission_name_set & router_name_set
        update_formset = update_formset_class(
            initial=[row_dict for name, row_dict in permission_dict.items() if name in update_name_list])


    return render(request,'rbac/multi_permissions.html',locals())


def multi_permissions_del(request,pk):
    '''
    批量页面的权限删除
    :param request:
    :param pk:
    :return:
    '''
    url = memory_reverse(request,'rbac:multi_permissions')
    if request.method == "GET":
        return render(request,'rbac/delete.html',{'cancel':url})
    models.Permission.objects.filter(id=pk).delete()
    return redirect(url)


def distribute_permissions(request):
    '''
    权限分配
    :param request:
    :return:
    '''

    user_id = request.GET.get('uid')

    # 业务中的用户表“app01.models.UserInfo"
    user_model_class = import_string(settings.RBAC_USER_MODLE_CLASS)
    user_obj = user_model_class.objects.filter(id=user_id).first()
    # 判断该用户是否存在
    if not user_obj:
        user_id = None

    role_id = request.GET.get('rid')
    role_obj = models.Role.objects.filter(id=role_id).first()
    # 判断选择的角色是否存在
    if not role_obj:
        role_id = None

    if request.method == 'POST' and request.POST.get('type') == 'role':
        role_id_list = request.POST.getlist('roles')
        # 用户和角色关系添加到第三张表（关系表）
        if not user_obj:
            return HttpResponse('请选择用户，然后在分配角色')
        user_obj.roles.set(role_id_list)

    if request.method == 'POST' and request.POST.get('type') == 'permission':
        permissions_id_list = request.POST.getlist('permissions')
        if not role_obj:
            return HttpResponse("请选择角色，然后再分配权限")
        role_obj.permissions.set(permissions_id_list)

    if user_id:
        # 获取当前用户所拥有的角色
        user_has_roles = user_obj.roles.all()
    else:
        user_has_roles = []


    # 如果选中的角色，优先显示选中角色所有的权限
    # 如果没有选择角色，才显示用户拥有的权限
    if role_obj:  # 选择角色
        user_has_permissions = role_obj.permissions.all()
        user_has_permissions_dict = {item.id: None for item in user_has_permissions}

    elif user_obj: # 未选择角色，但选择的用户
        # 获取当前用户所拥有的权限
        user_has_permissions = user_obj.roles.filter(permissions__id__isnull=False).values('id',
                                                                                           'permissions').distinct()

        user_has_permissions_dict = {item["permissions"]: None for item in user_has_permissions}
    else:
        user_has_permissions_dict = {}


    # 用户所拥有的角色，字典形式
    user_has_roles_dict = {item.id:None for item in user_has_roles }

    # 所有用户的信息
    all_user_list = user_model_class.objects.all()

    # 所有的角色信息
    all_role_list = models.Role.objects.all()


    menu_permission_list = []



    # 获取所有的菜单（一级菜单）
    all_menu_list = models.Menu.objects.values('id','title')

    all_menu_dict = {}
    for item in all_menu_list:
        item['children'] = []
        all_menu_dict[item['id']] = item

    # 获取所有的二级菜单
    all_second_menu_list = models.Permission.objects.filter(menu__isnull=False).values('id','title','menu_id')
    all_second_menu_dict = {}
    for row in all_second_menu_list:
        row['children'] = []
        all_second_menu_dict[row['id']] = row
        menu_id = row['menu_id']
        all_menu_dict[menu_id]['children'].append(row)



    # 获取所有的三级菜单
    all_permission_list = models.Permission.objects.filter(menu__isnull=True).values('id', 'title', 'pid_id')
    for row in all_permission_list:
        pid = row['pid_id']
        if not pid:
            continue
        all_second_menu_dict[pid]['children'].append(row)


    '''
    [
        {
          id:1,
          title:业务管理,
          children:[
                    {'id':11,
                     title:'账单列表',
                     children:[
                        {'id':12,title:'添加账单'}
                    ]},
                    {'id':22,title:'客户列表'},
          ]     
        },
    ]
    '''


    return render(request,'rbac/distribute_permissions.html',locals())





















